看完昨天的 prisma validator
的功能後,大家對 type safe
是不是又更了解了呢?今天補充一些情境讓你不得不用 prisma validator
以下是今天的 demo
會用到的 model
,簡單加上一個 User
的 model
然後用一對多的關聯式去 relation Post
model User {
id Int @id
email String @unique
name String?
posts Post[]
}
model Post {
id Int @id
author User @relation(fields: [userId], references: [id])
title String
published Boolean @default(false)
userId Int
}
每當我們 migrate DB
後 prisma client
會自動產生以下的 type
這邊來說就是 User
export declare type User = {
id: string
email: string
name: string | null
}
但這時我們可能會遇到一個情境會是,假設你有一個 function
然後需要定義 User
return
的 type
,但仔細看一下 User type
他並沒有任何關於 post
的內容 ,原因就是 prisma
預設不會 return relation
的 data
,同時也不會產生關於 post
的型別,所以這時候我們只能自己 customize
我們要的 User type
同時包含 post
的內容
所以你會去定義如以下的 UserWithPosts
以及 UserPersonalData
來區別 return
的 data
是否有 post
// 1: Define a type that includes the relation to `Post`
type UserWithPosts = {
id: string
email: string
name: string | null
posts: Post[]
}
// 2: Define a type that only contains a subset of the scalar fields
type UserPersonalData = {
email: string
name: string | null
}
以上的寫法雖然很有彈性,但其實對於日後維護會添加很多成本,原因是每當你重新 generate prisma client
都需要手動去 update
UserWithPosts
跟 UserPersonalData
的型別,但其實你不用這麼麻煩,prisma
有提供 utils function
自動給你你要的 type
import { Prisma } from '@prisma/client'
// 1: Define a type that includes the relation to `Post`
const userWithPosts = Prisma.validator<Prisma.UserDefaultArgs>()({
include: { posts: true },
})
// 2: Define a type that only contains a subset of the scalar fields
const userPersonalData = Prisma.validator<Prisma.UserDefaultArgs>()({
select: { email: true, name: true },
})
// 3: This type will include a user and all their posts
type UserWithPosts = Prisma.UserGetPayload<typeof userWithPosts>
以上的寫法可以讓整體的 code
更乾淨,同時對於日後維護也更方便
另外一個情境會是當我們使用 include
或是 select
的時候我們很難拿到 getUsersWithPosts
的 return type
async function getUsersWithPosts() {
const users = await prisma.user.findMany({ include: { posts: true } })
return users
}
所以常見的情況會是,我們要訂很多的 type
去拿到 getUsersWithPosts
return
的型別
// Function definition that returns a partial structure
async function getUsersWithPosts() {
const users = await prisma.user.findMany({ include: { posts: true } })
return users
}
// Extract `UsersWithPosts` type with
type ThenArg<T> = T extends PromiseLike<infer U> ? U : T
type UsersWithPosts = ThenArg<ReturnType<typeof getUsersWithPosts>>
// run inside `async` function
const usersWithPosts: UsersWithPosts = await getUsersWithPosts()
但其實我們可以直接用 Prisma.PromiseReturnType
就可以簡單拿到我們要的 type
了
import { Prisma } from '@prisma/client'
type UsersWithPosts = Prisma.PromiseReturnType<typeof getUsersWithPosts>
✅ 前端社群 :
https://lihi3.cc/kBe0Y